const fs = require('fs');
const path = require('path');
const https = require('https');
const http = require('http');
const { execSync } = require('child_process');
const os = require('os');

// FFmpeg下载配置
const FFMPEG_CONFIG = {
  windows: {
    url: 'https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-win64-gpl.zip',
    filename: 'ffmpeg-master-latest-win64-gpl.zip',
    extractDir: 'win64',
    binaryName: 'ffmpeg.exe',
    localPackages: [
      'ffmpeg-windows.zip',
      'ffmpeg-win64.zip',
      'ffmpeg-master-latest-win64-gpl.zip'
    ]
  },
  linux: {
    url: 'https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-linux64-gpl.tar.xz',
    filename: 'ffmpeg-master-latest-linux64-gpl.tar.xz',
    extractDir: 'linux64',
    binaryName: 'ffmpeg',
    localPackages: [
      'ffmpeg-linux.tar.xz',
      'ffmpeg-linux64.tar.xz',
      'ffmpeg-master-latest-linux64-gpl.tar.xz',
      'ffmpeg-linux.tar.gz',
      'ffmpeg-linux64.tar.gz'
    ]
  },
  darwin: {
    url: 'https://evermeet.cx/ffmpeg/getrelease/zip',
    filename: 'ffmpeg-macos.zip',
    extractDir: 'macos',
    binaryName: 'ffmpeg',
    localPackages: [
      'ffmpeg-macos.zip',
      'ffmpeg-mac.zip',
      'ffmpeg-osx.zip'
    ]
  }
};

// 创建目录
function createDirectory(dirPath) {
  if (!fs.existsSync(dirPath)) {
    fs.mkdirSync(dirPath, { recursive: true });
    console.log(`创建目录: ${dirPath}`);
  }
}

// 检查本地FFmpeg安装包
function findLocalFFmpegPackage(config) {
  const possiblePaths = [
    path.join(__dirname, '..', 'ffmpeg-packages'),
    path.join(__dirname, '..', 'packages'),
    path.join(__dirname, '..', 'assets'),
    path.join(__dirname, '..', 'binaries', 'packages'),
    path.join(process.cwd(), 'ffmpeg-packages'),
    path.join(process.cwd(), 'packages')
  ];

  for (const basePath of possiblePaths) {
    if (fs.existsSync(basePath)) {
      for (const packageName of config.localPackages) {
        const packagePath = path.join(basePath, packageName);
        if (fs.existsSync(packagePath)) {
          console.log(`找到本地FFmpeg安装包: ${packagePath}`);
          return packagePath;
        }
      }
    }
  }

  return null;
}

// 下载文件
function downloadFile(url, filepath) {
  return new Promise((resolve, reject) => {
    console.log(`开始下载: ${url}`);
    
    const protocol = url.startsWith('https:') ? https : http;
    const file = fs.createWriteStream(filepath);
    
    protocol.get(url, (response) => {
      if (response.statusCode !== 200) {
        reject(new Error(`下载失败，状态码: ${response.statusCode}`));
        return;
      }
      
      const totalSize = parseInt(response.headers['content-length'], 10);
      let downloadedSize = 0;
      
      response.on('data', (chunk) => {
        downloadedSize += chunk.length;
        const progress = ((downloadedSize / totalSize) * 100).toFixed(2);
        process.stdout.write(`\r下载进度: ${progress}%`);
      });
      
      response.pipe(file);
      
      file.on('finish', () => {
        file.close();
        console.log('\n下载完成!');
        resolve();
      });
      
      file.on('error', (err) => {
        fs.unlink(filepath, () => {}); // 删除不完整的文件
        reject(err);
      });
    }).on('error', reject);
  });
}

// 解压文件
function extractFile(filepath, extractDir, platform) {
  return new Promise((resolve, reject) => {
    console.log(`开始解压: ${filepath}`);
    
    try {
      if (platform === 'win32') {
        // Windows使用内置解压
        const { spawn } = require('child_process');
        const unzip = spawn('powershell', [
          'Expand-Archive',
          '-Path', filepath,
          '-DestinationPath', extractDir,
          '-Force'
        ]);
        
        unzip.on('close', (code) => {
          if (code === 0) {
            console.log('解压完成!');
            resolve();
          } else {
            reject(new Error(`解压失败，退出码: ${code}`));
          }
        });
      } else {
        // Linux/macOS使用tar解压
        const fileExt = path.extname(filepath).toLowerCase();
        let extractCommand;
        
        if (fileExt === '.tar.xz') {
          extractCommand = `tar -xf "${filepath}" -C "${extractDir}"`;
        } else if (fileExt === '.tar.gz' || fileExt === '.tgz') {
          extractCommand = `tar -xzf "${filepath}" -C "${extractDir}"`;
        } else if (fileExt === '.zip') {
          extractCommand = `unzip -o "${filepath}" -d "${extractDir}"`;
        } else {
          reject(new Error(`不支持的文件格式: ${fileExt}`));
          return;
        }
        
        execSync(extractCommand, { stdio: 'inherit' });
        console.log('解压完成!');
        resolve();
      }
    } catch (error) {
      reject(error);
    }
  });
}

// 查找FFmpeg二进制文件
function findFFmpegBinary(extractDir, binaryName) {
  const searchPaths = [
    path.join(extractDir, binaryName),
    path.join(extractDir, 'bin', binaryName),
    path.join(extractDir, 'ffmpeg', binaryName),
    path.join(extractDir, 'ffmpeg-master-latest-win64-gpl', 'bin', binaryName),
    path.join(extractDir, 'ffmpeg-master-latest-linux64-gpl', 'bin', binaryName),
    path.join(extractDir, 'ffmpeg-master-latest-macos64-gpl', 'bin', binaryName)
  ];
  
  for (const searchPath of searchPaths) {
    if (fs.existsSync(searchPath)) {
      return searchPath;
    }
  }
  
  return null;
}

// 复制FFmpeg到目标目录
function copyFFmpegToBinaries(sourcePath, targetPath) {
  createDirectory(path.dirname(targetPath));
  fs.copyFileSync(sourcePath, targetPath);
  
  // 在Linux/macOS上设置执行权限
  if (process.platform !== 'win32') {
    fs.chmodSync(targetPath, '755');
  }
  
  console.log(`FFmpeg已复制到: ${targetPath}`);
}

// 主函数
async function main() {
  const platform = process.platform;
  // 将 win32 映射到 windows
  const platformKey = platform === 'win32' ? 'windows' : platform;
  const config = FFMPEG_CONFIG[platformKey];
  
  if (!config) {
    console.error(`不支持的操作系统: ${platform}`);
    process.exit(1);
  }
  
  const binariesDir = path.join(__dirname, '..', 'binaries');
  const downloadDir = path.join(binariesDir, 'downloads');
  const extractDir = path.join(downloadDir, config.extractDir);
  const downloadPath = path.join(downloadDir, config.filename);
  const targetPath = path.join(binariesDir, config.binaryName);
  
  try {
    // 检查是否已经存在
    if (fs.existsSync(targetPath)) {
      console.log('FFmpeg已存在，跳过安装');
      return;
    }
    
    // 创建目录
    createDirectory(binariesDir);
    createDirectory(downloadDir);
    
    // 首先尝试使用本地安装包
    const localPackage = findLocalFFmpegPackage(config);
    let packagePath = downloadPath;
    
    if (localPackage) {
      console.log('使用本地FFmpeg安装包');
      packagePath = localPackage;
    } else {
      console.log('未找到本地安装包，尝试网络下载');
      
      try {
        // 尝试下载FFmpeg
        await downloadFile(config.url, downloadPath);
      } catch (downloadError) {
        console.error('网络下载失败:', downloadError.message);
        console.log('\n=== 解决方案 ===');
        console.log('1. 检查网络连接');
        console.log('2. 使用本地安装包:');
        console.log(`   - 将FFmpeg安装包放在以下目录之一:`);
        console.log(`     * ${path.join(__dirname, '..', 'ffmpeg-packages')}`);
        console.log(`     * ${path.join(__dirname, '..', 'packages')}`);
        console.log(`     * ${path.join(__dirname, '..', 'assets')}`);
        console.log(`   - 支持的包名: ${config.localPackages.join(', ')}`);
        console.log('3. 手动下载FFmpeg并放置到上述目录');
        console.log('4. 重新运行: npm run download-ffmpeg');
        
        process.exit(1);
      }
    }
    
    // 解压文件
    await extractFile(packagePath, extractDir, platform);
    
    // 查找FFmpeg二进制文件
    const ffmpegPath = findFFmpegBinary(extractDir, config.binaryName);
    
    if (!ffmpegPath) {
      throw new Error('无法找到FFmpeg二进制文件');
    }
    
    // 复制到目标位置
    copyFFmpegToBinaries(ffmpegPath, targetPath);
    
    // 清理下载文件（只清理临时下载的文件，不清理本地包）
    if (!localPackage) {
      console.log('清理临时文件...');
      fs.rmSync(downloadDir, { recursive: true, force: true });
    }
    
    console.log('FFmpeg安装完成!');
    
  } catch (error) {
    console.error('FFmpeg安装失败:', error.message);
    process.exit(1);
  }
}

// 运行主函数
if (require.main === module) {
  main();
}

module.exports = { main }; 